package com.chenju.invokechainservice.service.impl;

import com.chenju.invokechainservice.dao.TAnnotationNodeRepository;
import com.chenju.invokechainservice.domain.*;
import com.chenju.invokechainservice.service.TAnnotationNodeService;
import com.chenju.invokechainservice.utils.FunnyListsUtils;
import com.chenju.invokechainservice.utils.FunnyStringUtils;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
public class TAnnotationNodeServiceImplement implements TAnnotationNodeService {
    private final TAnnotationNodeRepository repository;

    public TAnnotationNodeServiceImplement(TAnnotationNodeRepository repository) {
        this.repository = repository;
    }

    @Override
    public List<TAnnotationNode> findByName(String name) {
        return repository.findByName(name);
    }

    @Override
    public TAnnotationNode save(TAnnotationNode node) {
        return repository.save(node);
    }

    @Override
    public BaseNode parseAnnotation(BaseNode bNode, List<AnnotationNode> annotations) {
        if (annotations == null) {
            return bNode;
        }
        if (bNode == null) {
            return null;
        }
        List<TAnnotationNode> annotationNodes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(annotations)) {
            annotations.forEach(r -> {
                // 设置annotationValues
                String annotationClassName = Type.getType(r.desc).getClassName();
                TAnnotationNode annotationNode = new TAnnotationNode(annotationClassName);
                // 用于处理List中包含List的情况，因为这种情况Neo4j无法存储并报错
                List<String> stringValues = new ArrayList<>();
                if (r.values != null) {
                    for (Object obj : r.values) {
                        if (obj instanceof List){
                            stringValues.add(obj.toString());
                        } else if (obj instanceof String){
                            stringValues.add((String) obj);
                        } else {
                            stringValues.add(obj.toString());
                        }
                    }
                }
                annotationNode.setValues(stringValues);

                Map<String, String> valueMap = FunnyListsUtils.groupItems(stringValues);
                annotationNodes.add(save(annotationNode));
                // 当bNode是ClassNode时
                if (bNode instanceof TClassNode) {
                    if ("org.springframework.web.bind.annotation.RestController".equals(annotationClassName)) {
                        ((TClassNode) bNode).setController(true);
                    }
                    if ("org.springframework.web.bind.annotation.RequestMapping".equals(annotationClassName)) {
                        ((TClassNode) bNode).setMappingPath(Optional.ofNullable(valueMap.get("value")).orElse(valueMap.get("path")));
                    }
                    if ("org.springframework.cloud.openfeign.FeignClient".equals(annotationClassName)) {
                        String superApplication = valueMap.get("value");
                        ((TClassNode) bNode).setFeignClient(true);
                        ((TClassNode) bNode).setSuperApplication(superApplication);
                    }
                    ((TClassNode) bNode).setAnnotations(annotationNodes);
                } else if (bNode instanceof TMethodNode) {
                    if (annotationClassName.contains("Mapping")) {
                        ((TMethodNode) bNode).setInterface(true);
                        if ("org.springframework.web.bind.annotation.RequestMapping".equals(annotationClassName)) {
                            String requestMethod = valueMap.get("method");
                            String mappingPath = Optional.ofNullable(valueMap.get("value")).orElse(valueMap.get("path"));
                            ((TMethodNode) bNode).setMappingPath(mappingPath);
                            ((TMethodNode) bNode).setRequestMethod(requestMethod);
                        } else {
                            String requestMethod = FunnyStringUtils.findLastName(annotationClassName).replace("Mapping","").toUpperCase();
                            String mappingPath = Optional.ofNullable(valueMap.get("value")).orElse(valueMap.get("path"));
                            ((TMethodNode) bNode).setRequestMethod(requestMethod);
                            ((TMethodNode) bNode).setMappingPath(mappingPath);
                        }
                    }
                    if ("org.aspectj.lang.annotation.Before".equals(annotationClassName) || "org.aspectj.lang.annotation.After".equals(annotationClassName) || "org.aspectj.lang.annotation.AfterReturning".equals(annotationClassName) || "org.aspectj.lang.annotation.AfterThrowing".equals(annotationClassName) || "org.aspectj.lang.annotation.Around".equals(annotationClassName)) {
                        ((TMethodNode) bNode).setAdvices(true);
                    }
                    if ("org.aspectj.lang.annotation.Pointcut".equals(annotationClassName)) {
                        ((TMethodNode) bNode).setPointcut(true);
                    }
                    ((TMethodNode) bNode).setAnnotations(annotationNodes);
                }
            });

        }

        return bNode;
    }

    @Override
    public Map<String, String> findAnnotationParamsMapByAnnotationClass(List<TAnnotationNode> annotations, List<String> classesName) {
        if (CollectionUtils.isEmpty(classesName) || CollectionUtils.isEmpty(annotations)) {
            return null;
        }
        for (TAnnotationNode annotation : annotations) {
            if (classesName.contains(annotation.getName())){
                return FunnyListsUtils.groupItems(annotation.getValues());
            }
        }
        return null;
    }

    @Override
    public Map<String, String> findAnnotationParamsMapByAnnotationClass(List<TAnnotationNode> annotations, String className) {
        if (className == null || "".equals(className)){
            return null;
        }
        if (CollectionUtils.isEmpty(annotations)){
            return null;
        }
        for (TAnnotationNode annotation : annotations){
            if (className.equals(annotation.getName())){
                return FunnyListsUtils.groupItems(annotation.getValues());
            }
        }
        return null;
    }


}
